/**
 * @PoolInvocationHandler.java  COPYRIGHT xiaojian
 * 
 * Created on 2019年7月29日 下午5:21:29
 */
package xj.toolkit.redis.shard;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

import redis.clients.jedis.ShardedJedisPipeline;
import xj.toolkit.redis.PipelineExecutor;

/**
 * @author <a href="mailto:cxj2000@gmail.com">xiaojian.cao</a>
 *
 */
public class ShardedPoolInvocationHandler implements InvocationHandler {

	private static final Logger logger = LoggerFactory.getLogger(ShardedPoolInvocationHandler.class);
	private ShardedJedis2Pool jedis2Pool = null;

	public ShardedPoolInvocationHandler(ShardedJedis2Pool jedisPool) {
		Preconditions.checkArgument(jedisPool != null);
		this.jedis2Pool = jedisPool;
	}

	public Object invoke(Object proxy, Method method, Object args[]) throws Throwable {
		ShardedJedis2 jedis = jedis2Pool.getResource();

		if (jedis == null) {
			throw new IllegalStateException("Cannot get redis connection.");
		}

		if (method.getName().equals("sync")) {
			try {
				sync((PipelineExecutor) args[0], jedis);
			} catch (Exception exception) {
				throw exception;
			} finally {
				jedis.close();
//				jedis2Pool.returnResource(jedis);
			}
			return null;
		}

		if (method.getName().equals("syncAndReturnAll")) {
			try {
				return syncAndReturnAll((PipelineExecutor) args[0], jedis);
			} catch (Exception exception) {
				throw exception;
			} finally {
				jedis.close();
//				jedis2Pool.returnResource(jedis);
			}
		}

		Object value = null;

		try {
			value = method.invoke(jedis, args);
		} catch (Exception exception) {
			throw exception;
		} finally {
			jedis.close();
//			jedis2Pool.returnResource(jedis);
		}

		logger.debug("Execute jedis command[" + method.getName() + "], args[" + ArrayUtils.toString(args) + "], result["
				+ String.valueOf(value) + "].");

		return value;
	}

	private void sync(PipelineExecutor executor, ShardedJedis2 jedis) {
		ShardedJedisPipeline p = jedis.pipelined();
		executor.pipelined(p);
		p.sync();
	}

	private List<Object> syncAndReturnAll(PipelineExecutor executor, ShardedJedis2 jedis) {
		ShardedJedisPipeline p = jedis.pipelined();
		executor.pipelined(p);
		return p.syncAndReturnAll();
	}
}
